﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using System.Reflection;
namespace Lion
{
    public static class ObjectAssembler
    {
        public static void SaveOrUpdate(object Object, out Exception Exception)
        {
            Exception = null;
            using (var session = NHibernateUtil.OpenSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    try
                    {
                        session.SaveOrUpdate(Object);
                    }
                    catch (Exception ex)
                    {
                        Exception = ex;
                    }
                    transaction.Commit();
                }
            }

        }

        public static void Save(object Object, out Exception Exception)
        {
            Exception = null;
            using (var session = NHibernateUtil.OpenSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    try
                    {
                        session.Save(Object);
                    }
                    catch (Exception ex)
                    {
                        Exception = ex;
                        transaction.Rollback();
                        return;
                    }
                    transaction.Commit();


                }
            }
        }

        public static void Delete(object Object, out Exception Exception)
        {
            Exception = null;
            using (var session = NHibernateUtil.OpenSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    try
                    {
                        session.Delete(Object);
                    }
                    catch (Exception ex)
                    {
                        Exception = ex;
                        transaction.Rollback();
                        return;
                    }
                    transaction.Commit();


                }
            }
        }

        public static void SaveCachedObject<K, T>(ICachedCollection<K, T> CachedObject, K ID, T Object, out Exception Exception) where T : class,ICachedCollection<K, T>
        {
            ObjectAssembler.Save(CachedObject, out Exception);
            CachedObject.AddToCache(ID, Object);

        }

        public static void SaveOrUpdateCachedObject<K, T>(ICachedCollection<K, T> cachedObject, K ID, T Object, out Exception exception) where T : class,ICachedCollection<K, T>
        {
            ObjectAssembler.SaveOrUpdate(cachedObject, out exception);
            cachedObject.AddToCache(ID, Object);
        }

        public static bool DeleteCachedObject<K, T>(ICachedCollection<K, T> cachedObject, K ID, out Exception exception) where T : class,ICachedCollection<K, T>
        {
            ObjectAssembler.Delete(cachedObject, out exception);
            return cachedObject.RemoveFromCache(ID);
        }
       
        public static IList<T> GetAllObjects<T>()
        {
            string typeName = typeof(T).Name;
            string hql = string.Format("from {0}", typeName);
            IList<T> allItems = null;
            try
            {
                using (var session = NHibernateUtil.OpenSession())
                {
                    IQuery query = session.CreateQuery(hql);
                    allItems = query.List<T>();

                }
            }
            catch
            {
                throw;
            }
            return allItems;
        }

        public static IList<T> GetFilteredObject<T>(System.Linq.Expressions.Expression<Func<T>> FilterExpression) where T : class
        {
            IList<T> result = null;
            using (ISession session = NHibernateUtil.OpenSession())
            {
                IQueryOver<T, T> query = session.QueryOver<T>(FilterExpression);
                result = query.List<T>();
            }
            return result;
        }

        public static IList<T> ExecuteHQL<T>(string HQL, params object[] Objects)
        {
            IList<T> allObjects = null;
            using (var session = NHibernateUtil.OpenSession())
            {

                IQuery query = session.CreateQuery(HQL);
                for (int i = 0; i < Objects.Length; i++)
                {
                    query.SetParameter(query.NamedParameters[i], Objects[i]);
                }
                allObjects = query.List<T>();

            }
            return allObjects;
        }

        public static void ClearAllTypes()
        {

            var cachedType = typeof(ICachedCollection<,>);
            Type[] allTypes = Assembly.GetExecutingAssembly().GetTypes();


            foreach (var type in allTypes)
            {
                foreach (var inter in type.GetInterfaces())
                {

                    if (inter.IsGenericType && inter.GetGenericTypeDefinition() == cachedType)
                    {
                        object obj = Activator.CreateInstance(type);
                        MethodInfo method = type.GetMethod("ClearCollection");
                        method.Invoke(obj, null);
                    }
                }

            }



        }

        public static void BulkInsert(IEnumerable<object> Collection, out Exception Exception, int Batchsize = 16)
        {
            Exception = null;
            using (IStatelessSession session = NHibernateUtil.OpenStatelessSession().SetBatchSize(Batchsize))
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    try
                    {
                        foreach (object obj in Collection)
                        {
                            session.Insert(obj);
                        }
                        transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        Exception = ex;
                    }
                }
            }
        }
    }
}
